import { Component, Input, OnInit } from '@angular/core';
import { NziModalService } from 'ng-zorro-iop/modal/nzi-modal.service';
import { NzMessageService } from "ng-zorro-antd";
import { FcsService } from "../../service/fcs.service";
import { FormArray, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
import { debounceTime, distinctUntilChanged, first, map, switchMap } from 'rxjs/operators';
import { Observable, Subscriber } from 'rxjs';
import { Environment } from 'environments/environment';
import { randomBytes } from 'crypto';

@Component({
  selector: 'app-domain-create',
  templateUrl: './domain-create.component.html',
  styleUrls: ['./domain-create.component.less']
})
export class DomainCreateComponent implements OnInit {
  @Input() domainInstance;
  domainForm: FormGroup;
  httpTriggerList = [];
  groupDiaplayNameList = [];
  routeConfigList = [];
  enableHttps = false;
  invokeHost = "";
  tableLoading = true;

  constructor(
    private fcsService: FcsService,
    private modalService: NziModalService,
    private msgService: NzMessageService,
    private fb: FormBuilder
  ) {
    let host = Environment.application.httpTriggerHost.split("//");
    this.invokeHost = host[1];
    this.domainForm = this.fb.group({
      domainName: ["",
        [
          Validators.required,
          Validators.pattern(/^(?=^.{3,255}$)[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+$/)
        ],
        [this.nameDuplicateValidator()]
      ],
      protocol: ["HTTP", [Validators.required]],
      // 证书配置
      certName: [""],
      certCertificate: [""],
      certKey: [""],
      // 路由设置
      // routeConfig demo
      // {
      //   "path": "/",
      //   "triggerId": "acebd93d-bd60-4452-833b-26258d321c6d",
      //   "triggerName": "test",
      //   "groupName": "ctzz68m5v5",
      //   "groupDisplayName": "test-customcontainer",
      //   "functionName": "http-trigger",
      //   "targetType": 1,
      //   "targetName": "LATEST"
      // }
      routeConfig: this.fb.array([]),
    });
  }

  async ngOnInit() {
    // 添加时间戳和随机数字段
    this.domainForm.addControl('timestamp', new FormControl(Date.now()));
    this.domainForm.addControl('nonce', new FormControl(randomBytes(5).toString(36).substring(0, 9)));

    await this.initTriggerList();
    if (this.domainInstance) {
      await this.dataInit();
    } else {
      this.addRouteConfig();
    }
    this.tableLoading = false;
  }

  successFun() {
    this.msgService.success('复制成功');
  }

  dataInit() {
    return new Promise((resolve, reject) => {
      this.domainForm.get("domainName").disable();
      this.domainForm.get("domainName").setValue(this.domainInstance.domainName);
      this.domainForm.get("domainName").markAsDirty();
      this.domainForm.get("protocol").setValue(this.domainInstance.protocol);
      let routeConfigString = this.domainInstance.routeConfig;
      if (routeConfigString != "") {
        let routeConfigArray = JSON.parse(routeConfigString);
        routeConfigArray.forEach(item => {
          let newFormGroup = this.fb.group({
            path: [item.path, [
              Validators.required,
              Validators.pattern(/^\/[\W\w]*/)
            ]],
            group: [null, [
              Validators.required
            ]],
            function: [null, [
              Validators.required
            ]],
            version: [null, [
              Validators.required
            ]],
          });
          let triggerInfoList = this.httpTriggerList.filter(t => t.id == item.triggerId);
          let triggerInfo = {
            functionList: [],
            versionList: [],
            groupName: "",
            functionName: "",
            targetName: "",
            triggerInfo: null,
          };

          if (triggerInfoList.length > 0) {
            // other info
            triggerInfo.triggerInfo = triggerInfoList[0];
            triggerInfo.groupName = triggerInfo.triggerInfo["groupName"];
            triggerInfo.functionName = triggerInfo.triggerInfo["funcName"];
            triggerInfo.targetName = triggerInfo.triggerInfo["targetName"];
            newFormGroup.get("group").setValue(triggerInfo.groupName);
            newFormGroup.get("function").setValue(triggerInfo.functionName);
            newFormGroup.get("version").setValue(triggerInfo.targetName);
            // function list
            let functionArray = [];
            this.httpTriggerList.forEach(item => {
              if (item["groupName"] == triggerInfo.groupName) {
                functionArray.push(item["funcName"]);
              }
            });
            triggerInfo.functionList = Array.from(new Set(functionArray));
            // version list
            let versionArray = [];
            this.httpTriggerList.forEach(item => {
              if (item["groupName"] == triggerInfo.groupName && item["funcName"] == triggerInfo.functionName) {
                let data = {
                  key: "",
                  value: item["targetName"],
                };
                if (item["targetType"] == 1) {
                  data.key = "版本: " + item["targetName"];
                } else {
                  data.key = "别名: " + item["targetName"];
                }
                versionArray.push(data);
              }
            });
            triggerInfo.versionList = versionArray;
          }
          newFormGroup.get("path").markAsDirty();
          newFormGroup.get("group").markAsDirty();
          newFormGroup.get("function").markAsDirty();
          newFormGroup.get("version").markAsDirty();
          this.routeConfigList.push(triggerInfo); // 先添加元信息
          this.routeConfig.push(newFormGroup); // 再增加表单信息
        });
      }
      this.addRouteConfig();

      if (this.domainInstance.protocol == "HTTP,HTTPS") {
        this.fcsService.getDomainDetail(this.domainInstance.id).subscribe(
          data => {
            this.domainInstance = data;
            this.domainForm.get("certName").setValue(this.domainInstance.certName);
            this.domainForm.get("certCertificate").setValue(this.domainInstance.certCertificate);
            this.domainForm.get("certKey").setValue(this.domainInstance.certKey);
            resolve(true);
          },
          err => {
            resolve(false);
          }
        );
      } else {
        resolve(true);
      }
    });
  }

  initTriggerList() {
    return new Promise((resolve, reject) => {
      this.fcsService.getTriggerList("0", "0", 1, 10000, "", "http").subscribe(res => {
        if (res.data) {
          this.httpTriggerList = res.data;
          // 1. group
          let groupNameList = [];
          let dataArray = [];
          this.httpTriggerList.forEach(item => {
            if (groupNameList.indexOf(item["groupName"]) < 0) {
              dataArray.push({
                key: item["groupDisplayName"],
                value: item["groupName"],
              });
              groupNameList.push(item["groupName"])
            }
          });
          this.groupDiaplayNameList = dataArray;
        }
        resolve(true);
      }, err => {
        resolve(false);
      });
    });
  }

  get routeConfig(): FormArray {
    return this.domainForm.get('routeConfig') as FormArray;
  }
  removeRouteConfig(idx): void {
    this.routeConfig.removeAt(idx);
    this.routeConfigList.splice(idx, 1);
  }
  addRouteConfig(): void {
    let control = this.routeConfig.controls[this.routeConfig.length - 1];
    if (this.routeConfig.length == 0 ||
      !!control.get("path") || !!control.get("group") || !!control.get("function") || !!control.get("version")) {
      let newFormGroup = this.fb.group({
        path: ["", [
          Validators.required,
          Validators.pattern(/^\/[\W\w]*/)
        ]],
        group: [null, [
          Validators.required
        ]],
        function: [null, [
          Validators.required
        ]],
        version: [null, [
          Validators.required
        ]],
      });
      this.routeConfig.push(newFormGroup);
      this.routeConfigList.push({
        functionList: [],
        versionList: [],
        groupName: "",
        functionName: "",
        targetName: "",
        triggerInfo: null,
      });
    }
  }

  protocolChange(event) {
    if (event == "HTTP,HTTPS") {
      this.enableHttps = true;
      this.domainForm.get("certName").setValidators([
        Validators.required,
        Validators.pattern(/^[A-Za-z_][A-Za-z0-9_-]*$/)
      ]);
      this.domainForm.get("certCertificate").setValidators([Validators.required]);
      this.domainForm.get("certKey").setValidators([Validators.required]);
    } else {
      this.enableHttps = false;
      this.domainForm.get("certName").clearValidators();
      this.domainForm.get("certName").reset();
      this.domainForm.get("certCertificate").clearValidators();
      this.domainForm.get("certCertificate").reset();
      this.domainForm.get("certKey").clearValidators();
      this.domainForm.get("certKey").reset();
    }
  }

  groupChange(idx, event) {
    // 2. function
    let dataArray = [];
    this.httpTriggerList.forEach(item => {
      if (item["groupName"] == event) {
        dataArray.push(item["funcName"]);
      }
    });
    this.routeConfigList[idx].functionList = Array.from(new Set(dataArray));
    this.routeConfigList[idx].groupName = event;
    this.routeConfigList[idx].functionName = "";
    this.routeConfigList[idx].targetName = "";
    this.routeConfig.controls[idx].get("function").reset();
    this.routeConfig.controls[idx].get("version").reset();
    this.routeConfigList[idx].versionList = [];
    this.routeConfigList[idx].triggerInfo = null;

    if (idx == this.routeConfig.length - 1) {
      this.addRouteConfig();
    }
  }
  functionChange(idx, event) {
    // 3. version
    let dataArray = [];
    this.httpTriggerList.forEach(item => {
      if (item["groupName"] == this.routeConfigList[idx].groupName && item["funcName"] == event) {
        let data = {
          key: "",
          value: item["targetName"],
        };
        if (item["targetType"] == 1) {
          data.key = "版本: " + item["targetName"];
        } else {
          data.key = "别名: " + item["targetName"];
        }
        dataArray.push(data);
      }
    });
    this.routeConfigList[idx].versionList = dataArray;
    this.routeConfigList[idx].functionName = event;
    this.routeConfigList[idx].targetName = "";
    this.routeConfig.controls[idx].get("version").reset();
    this.routeConfigList[idx].triggerInfo = null;

    if (idx == this.routeConfig.length - 1) {
      this.addRouteConfig();
    }
  }
  versionChange(idx, event) {
    this.httpTriggerList.forEach(item => {
      if (item["groupName"] == this.routeConfigList[idx].groupName && item["funcName"] == this.routeConfigList[idx].functionName && item["targetName"] == event) {
        this.routeConfigList[idx].triggerInfo = item;
      }
    });
    this.routeConfigList[idx].targetName = event;

    if (idx == this.routeConfig.length - 1) {
      this.addRouteConfig();
    }
  }

  pathChange(idx, event) {
    if (idx == this.routeConfig.length - 1) {
      this.addRouteConfig();
    }
    this.pathDuplicateValidator(idx);
  }

  nameDuplicateValidator() {
    return (control: FormControl): any => {
      return control.valueChanges.pipe(
        distinctUntilChanged(),
        debounceTime(400),
        switchMap(() => this.isUserNameExist(control.value)),
        map(res => res['exist'] === true ? { duplicated: true } : null),
        first()
      );
    };
  }
  isUserNameExist(name: string): Observable<any> {
    if ((this && !this.domainInstance && name) || (this.domainInstance && name && name !== this.domainInstance.domainName)) {
      return this.fcsService.determineDomainDuplicate(name);
    }
    return new Observable((observer: Subscriber<any>) => {
      setTimeout(() => {
        observer.next({ exist: false });
      }, 2000);
    });
  }
  pathDuplicateValidator(idx) {
    if (this.routeConfig) {
      let counts = [];
      for (let i = 0; i < this.routeConfig.length; i++) {
        let control = this.routeConfig.controls[i].get("path");
        let val = control.value;
        if (control.dirty) {
          control.updateValueAndValidity();
        }
        if (counts[val] === undefined) {
          counts[val] = i;
        } else {
          if (counts[val] == idx) {
            this.routeConfig.controls[idx].get("path").setErrors({
              exist: true
            });
          } else {
            control.setErrors({
              exist: true
            });
          }
        }
      }
    }
  }

  submitForm() {
    for (let item in this.domainForm.controls) {
      if (item != "routeConfig" && item != "domainName") {
        this.domainForm.get(item).markAsDirty();
        this.domainForm.get(item).updateValueAndValidity();
      }
    }
    if (!this.domainForm.get("domainName").dirty) {
      this.domainForm.get("domainName").markAsDirty();
      this.domainForm.get("domainName").updateValueAndValidity();
    }
    this.routeConfig.controls.forEach(group => {
      if (group.get("path").dirty || group.get("group").dirty || group.get("function").dirty || group.get("version").dirty) {
        group.get("path").markAsDirty();
        group.get("group").markAsDirty();
        group.get("function").markAsDirty();
        group.get("version").markAsDirty();
      } else {
        group.get("path").clearValidators();
        group.get("path").clearAsyncValidators();
        group.get("group").clearValidators();
        group.get("group").clearAsyncValidators();
        group.get("function").clearValidators();
        group.get("function").clearAsyncValidators();
        group.get("version").clearValidators();
        group.get("version").clearAsyncValidators();
      }
      group.get("path").updateValueAndValidity();
      group.get("group").updateValueAndValidity();
      group.get("function").updateValueAndValidity();
      group.get("version").updateValueAndValidity();
    });

    return new Promise((resolve, reject) => {
      if (!this.domainForm.valid) {
        resolve(false);
      } else {
        // 组装请求数据
        let data = {
          domainName: this.domainForm.get("domainName").value,
          protocol: this.domainForm.get("protocol").value,
          routeConfig: "",
          certName: "",
          certCertificate: "",
          certKey: "",
        };
        if (this.enableHttps) {
          data.certName = this.domainForm.get("certName").value;
          data.certCertificate = this.domainForm.get("certCertificate").value;
          data.certKey = this.domainForm.get("certKey").value;
        }

        let routeConfigData = [];
        this.routeConfig.controls.forEach((group, idx) => {
          if (group.get("path").dirty || group.get("group").dirty || group.get("function").dirty || group.get("version").dirty) {
            // 这个地方八个参数每个都不能错！
            // 否则路径无法访问
            routeConfigData.push({
              "path": group.get("path").value,
              "triggerId": this.routeConfigList[idx].triggerInfo.id,
              "triggerName": this.routeConfigList[idx].triggerInfo.name,
              "groupName": this.routeConfigList[idx].triggerInfo.groupName,
              "groupDisplayName": this.routeConfigList[idx].triggerInfo.groupDisplayName,
              "functionName": this.routeConfigList[idx].triggerInfo.funcName,
              "targetType": this.routeConfigList[idx].triggerInfo.targetType,
              "targetName": this.routeConfigList[idx].triggerInfo.targetName,
            });
          }
        });

        if (routeConfigData.length > 0) {
          data.routeConfig = JSON.stringify(routeConfigData);
        }

        // 发送请求
        if (!this.domainInstance) {
          // 创建
          this.fcsService.createDomain(data).subscribe(
            data => {
              if (data && data.domainName) {
                resolve(true);
                this.msgService.success(data['message'] || '自定义域名创建成功！');
              } else {
                resolve(false);
                this.msgService.error(data['message']);
              }
            }, err => {
              resolve(false);
            }
          );
        } else {
          // 更新
          this.fcsService.updateDomain(this.domainInstance.id, data).subscribe(
            data => {
              if (data && data.domainName) {
                resolve(true);
                this.msgService.success(data['message'] || '自定义域名配置成功！');
              } else {
                resolve(false);
                this.msgService.error(data['message']);
              }
            }, err => {
              resolve(false);
            }
          );
        }
      }
    });
  }
}
